﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TimberSmart.Data.Repositories
{
    // This is just a general toolkit for our repositories. Put anything good in here. You don't have to inherit this.
    public abstract class RepositoryBase
    {
        protected DbContext _context { get; set; }

        public RepositoryBase(DbContext context)
        {
            // Make sure we're given a context.
            if (context == null) throw new ArgumentNullException("context");

            this._context = context; 
        }

        protected IEnumerable<T> FindAll<T>()
            where T: class
        {
            return _context.Set<T>();
        }

        protected IEnumerable<T> FindAll<T>(Func<T, bool> criteria)
            where T: class
        {
            return _context.Set<T>().Where(criteria);
        }

        protected IEnumerable<T> FindAll<T>(Func<T, bool> criteria, Func<T, object> orderBy)
            where T: class
        {
            return _context.Set<T>().Where(criteria).OrderBy(orderBy);
        }

        protected IEnumerable<T> FindAll<T>(Func<T, bool> criteria, Func<T, object> orderBy, bool descending)
            where T: class
        {
            if (descending)
                return _context.Set<T>().Where(criteria).OrderByDescending(orderBy);
            else
                return _context.Set<T>().Where(criteria).OrderBy(orderBy);
        }

        protected T FindById<T>(int Id)
            where T: class
        {
            // Find the entity with its Id.
            return _context.Set<T>().Find(Id);
        }

        protected void Add<T>(T entity)
            where T: class
        {
            var entry = _context.Entry(entity);

            // Get the entity's state, if it's attached, just add it. Otherwise mark it's state as Added.
            if (entry.State == System.Data.EntityState.Detached)
            {
                _context.Set<T>().Add(entity);
            }
            else
            {
                entry.State = System.Data.EntityState.Added;
            }
        }

        protected void Update<T>(T entity)
            where T: class
        {
            var entry = _context.Entry(entity);

            // Get the state of the entity, if it's detached, attach it.
            if (entry.State == System.Data.EntityState.Detached)
            {
                _context.Set<T>().Attach(entity);
            }

            // Set the state entry to modified.
            entry.State = System.Data.EntityState.Modified;
        }

        protected void Delete<T>(T entity)
            where T: class
        {            
            var entry = _context.Entry(entity);

            // Get the state of the entity, if it's detached, attach it.
            if (entry.State == System.Data.EntityState.Detached)
            {
                _context.Set<T>().Attach(entity);
            }

            // Set the entry state to deleted.
            _context.Set<T>().Remove(entity);
        }

        protected void Delete<T>(int Id)
            where T: class
        {
            // Get the entity via it's Id.
            var entity = FindById<T>(Id);

            // If you find it, delete it using the above method.
            if (entity != null)
            {
                Delete<T>(entity);
            }
        }
    }
}
